<template>
  <div class="q-gutter-md">
    <div class="row justify-center">
      <q-file
        class="col-lg-4 col-md-6 col-xs-10"
        ref="file"
        filled
        v-model="files"
        label="请选择excel文件"
        accept=".xlsx"
        :rules="[val => !!val || '请选择excel文件']"
      >
        <template v-slot:prepend>
          <q-icon name="attach_file" />
        </template>
        <template v-if="files" v-slot:append>
          <q-icon name="cancel" @click.stop.prevent="files = null" class="cursor-pointer" />
        </template>
      </q-file>
    </div>

    <div class="row justify-center">
      <q-input
        class="col-lg-4 col-md-6 col-xs-10"
        filled
        v-model="titleRow"
        type="number"
        label="标题所在行"
        prefix="第"
        suffix="行"
      />
    </div>

    <div class="row justify-center">
      <q-input
        class="col-lg-4 col-md-6 col-xs-10"
        filled
        v-model="dataRow"
        type="number"
        label="数据开始行"
        prefix="第"
        suffix="行"
      />
    </div>

    <div class="row justify-center">
      <q-select
        class="col-lg-4 col-md-6 col-xs-10"
        filled
        v-model="sheet"
        label="选择表"
        :options="sheetOpt"
      />
    </div>
    <slot></slot>
  </div>
</template>

<script>
import * as XLSX from 'xlsx';
import { defineComponent } from 'vue';
import { convertDSTo26BS, convert26BSToDS } from 'src/lib/utils';

export default defineComponent({
  name: 'readFromFile',
  props: {
    uid: {
      type: String,
      default: 'uid'
    },
    titleLine: { // 标题行
      type: Number,
      default: 1
    },
    dataLine: { // 数据开始行
      type: Number,
      default: 2
    }
  },
  data () {
    return {
      files: null,
      titleRow: 1,
      dataRow: 2,
      sheet: '',
      sheetOpt: []
    }
  },
  mounted () {
    /* if (this.$q.localStorage.has(`selectFileConfig_${this.uid}`)) {
      this.titleRow = this.$q.localStorage.getItem(`selectFileConfig_${this.uid}`).title;
      this.dataRow = this.$q.localStorage.getItem(`selectFileConfig_${this.uid}`).data;
    } */

    this.$storage.get(`selectFileConfig_${this.uid}`, true).then(data => {
      if (data) {
        this.titleRow = data.title;
        this.dataRow = data.data;
      }
    });
  },
  methods: {
    do () { // 执行读取文件
      return new Promise(resolve => {
        if (this.$refs.file.validate()) {
          this.readFile().then(data => resolve(data));
        } else {
          resolve();
        }
      });
    },
    readFile () { // 读excel文件
      return new Promise((resolve) => {
        const reader = new FileReader();

        reader.onload = (e) => {
          const arrayBuffer = e.target.result;
          const binaryString = this.arrayBufferToBinaryString(arrayBuffer);

          const wb = XLSX.read(binaryString, { type: 'binary' });
          const sheetName = this.sheet || wb.SheetNames[0];

          const outdata = XLSX.utils.sheet_to_json(wb.Sheets[sheetName], { header: 'A' });
          resolve(this.parseData(outdata));
        };

        reader.readAsArrayBuffer(this.files);
      });
    },
    arrayBufferToBinaryString (buffer) {
      // 读取成Uint8Array，再转换为Unicode编码（Unicode占两个字节）
      const bytes = new Uint8Array(buffer);
      let binaryString = '';
      for (let i = 0; i < bytes.byteLength; i++) {
        binaryString += String.fromCharCode(bytes[i]);
      }
      return binaryString;
    },
    parseData (excelData) { // 解析数据
      const columns = [{ name: 'id', label: '序号', field: 'id', align: 'center' }];
      const data = [];

      // 添加列定义
      const titleLine = excelData[this.titleRow - 1];
      const dataKeys = Object.keys(excelData[this.dataRow - 1]); // 数据有的key
      const titleKeys = Object.keys(titleLine);
      const firstColIdx = Math.min(convert26BSToDS(titleKeys[0]), convert26BSToDS(dataKeys[0]));
      const lastColIdx = Math.max(convert26BSToDS(titleKeys[titleKeys.length - 1]), convert26BSToDS(dataKeys[dataKeys.length - 1]));

      for (let i = firstColIdx; i <= lastColIdx; i++) {
        const key = convertDSTo26BS(i);
        let label = titleLine[key] || '';

        // 空标题，向前列取值
        if (!label) {
          let j = i;
          do {
            label = titleLine[convertDSTo26BS(j)] || '';
            j -= 1;
          } while (j >= firstColIdx && !label);
        }

        // 有多行标题，向下取值合并
        if (this.dataRow - this.titleRow > 1) {
          for (let j = Number(this.titleRow) + 1; j < Number(this.dataRow); j++) {
            label += excelData[j - 1][key] || '';
          }
        }

        columns.push({
          name: key,
          label,
          field: key,
          align: 'center'
        });
      }

      // 添加数据
      for (let i = this.dataRow - 1; i < excelData.length; i++) {
        const row = excelData[i];
        for (const key in titleLine) {
          if (row[key] === undefined) row[key] = '';
        }

        row.id = i - this.dataRow + 2;
        data.push(row);
      }

      this.files = null;

      return { columns, data };
    },
    readSheet () { // 读excel文件
      const reader = new FileReader();

      reader.onload = (e) => {
        const arrayBuffer = e.target.result;
        const binaryString = this.arrayBufferToBinaryString(arrayBuffer);

        const wb = XLSX.read(binaryString, { type: 'binary' });

        this.sheetOpt = wb.SheetNames;
        this.sheet = wb.SheetNames[0];
      };

      reader.readAsArrayBuffer(this.files);
    }
  },
  watch: {
    titleRow (val) {
      /* this.$q.localStorage.set(`selectFileConfig_${this.uid}`, {
        title: val,
        data: this.dataRow
      }); */

      this.$storage.set(`selectFileConfig_${this.uid}`, { title: val, data: this.dataRow }, true);
    },
    dataRow (val) {
      /* this.$q.localStorage.set(`selectFileConfig_${this.uid}`, {
        title: this.titleRow,
        data: val
      }); */

      this.$storage.set(`selectFileConfig_${this.uid}`, { title: this.titleRow, data: val }, true);
    },
    titleLine (val) {
      this.titleRow = val;
    },
    dataLine (val) {
      this.dataRow = val;
    },
    files (val) {
      if (val) {
        this.readSheet();
      } else {
        this.sheet = '';
        this.sheetOpt = [];
      }
    }
  }
});
</script>
